#ifndef __OPTICAL_CLIP_DETECTOR_H
#define __OPTICAL_CLIP_DETECTOR_H

#include <string>
#include <vector>
#include <thread>
#include <numeric>
#include <pthread.h>
#include <iostream>
#include <condition_variable>
#include "opencv2/opencv.hpp"
#include <memory>
#include <atomic>
#include <opencv2/opencv.hpp>
#include "acl/acl.h"

struct message_pre {
    std::vector<std::string> filenames;
    std::vector<cv::Mat> frames;
    
};

struct message_Excute {
    std::string filename_visible;
    std::string filename_infrared;
    aclmdlDataset * detectData; // true if the processed data is divisible by 2, false otherwise
};

struct message_result {
    std::vector<std::string> filenames;
    std::vector<std::vector<float>> finalOutput;
};

template<typename T>
class Queue {
    std::queue<T> queue;
    mutable std::mutex mutex;
    std::condition_variable cond;

public:
    void push(T value) {
        std::lock_guard<std::mutex> lock(mutex);
        queue.push(std::move(value));
        cond.notify_one();
    }

    bool try_pop(T& value) {
        std::lock_guard<std::mutex> lock(mutex);
        if(queue.empty()) return false;
        value = std::move(queue.front());
        queue.pop();
        return true;
    }

    void wait_and_pop(T& value) {
        std::unique_lock<std::mutex> lock(mutex);
        cond.wait(lock, [this]{ return !queue.empty(); });
        value = std::move(queue.front());
        queue.pop();
    }

    // 添加此方法以允许外部通知所有等待的线程
    void notify_all() {
        cond.notify_all();
    }

    int get_size(){
        std::lock_guard<std::mutex> lock(mutex);
        if(queue.empty()) return 0;
        return queue.size();
    }
};

class AclLiteModel{
   public:
        AclLiteModel(const std::string modelPath="", const size_t deviceId = 0);
        ~AclLiteModel();
        bool init();
        void Execute(std::vector<cv::Mat> &frame, std::vector<std::vector<float>> &outputs);
        void Execute(std::vector<std::vector<float>> &features, std::vector<std::vector<float>> &outputs);
        aclrtContext getContext();

   private:
        aclmdlDesc *modelDesc;
        uint32_t modelId;
        size_t  modelInputSize;

        std::vector<void*> modelInputs;
        std::vector<size_t> inputSizeLists;

        size_t input_nums; 
        size_t outinput_nums; 

        std::vector<void*> outputDeviceLists;
        std::vector<void*> outputHostLists;
        std::vector<size_t> outputSizeLists;
        aclmdlDataset *input = nullptr;
        aclmdlDataset *output = nullptr; 
        std::string modelPath;
        size_t deviceId;

        aclrtContext context;
        aclrtRunMode  runMode;
};

class Yolov3CLIPDetector 
  {
  public:
    Yolov3CLIPDetector(const std::string modelInfPath="", const std::string modelVisPath="", const size_t deviceIdInf = 0, const size_t deviceIdVis = 0);
    ~Yolov3CLIPDetector();
    bool init();
    void initThread();
    void modelVisExecute();
    void modelInfExecute();
    void modelAllExecute();
    std::vector<message_result> inference(std::vector<std::string> &imageLists);
    void DestroyResource();
    void wait_forVis_completion();
    void wait_forInf_completion();
    void wait_forAll_completion();

  private:
    size_t  g_modelWidth_ = 256;
    size_t  g_modelHeight_ = 256;

    AclLiteModel Model_inf;
    AclLiteModel Model_vis;
    AclLiteModel Model_all;
    std::string tModel_inf_Path;
    std::string tModel_vis_Path;
    
    size_t preprocess_thread_num = 2;
    size_t postprocess_thread_num = 2;
    std::atomic<bool> done{false};

    int taskInf_counter = 0;
    Queue<message_pre>queueInf_pre;
    std::vector<message_result> resultsInf;
    std::condition_variable conda_Inf;
    std::mutex resultsInf_mutex;
    std::mutex outputInf_mutex;

    int taskVis_counter = 0;
    Queue<message_pre>queueVis_pre;
    std::vector<message_result> resultsVis;
    std::condition_variable conda_Vis;
    std::mutex resultsVis_mutex;
    std::mutex outputVis_mutex;

    int taskAll_counter = 0;
    Queue<message_pre>queueAll_pre;
    std::vector<message_result> resultsAll;
    std::condition_variable conda_All;
    std::mutex resultsAll_mutex;
    std::mutex outputAll_mutex;

    std::vector<std::thread> threads;
  };



#endif